#include "CAN.h"				// CAN driver
/*****************************************************************************
 *
 * Microchip DeviceNet Stack (Explicit Messaging Connection Object Source)
 *
 *****************************************************************************
 * FileName:        conn1.c
 * Dependencies:    
 * Processor:       PIC18F with CAN
 * Compiler:       	C18 02.20.00 or higher
 * Linker:          MPLINK 03.40.00 or higher
 * Company:         Microchip Technology Incorporated
 *
 * Software License Agreement
 *
 * The software supplied herewith by Microchip Technology Incorporated
 * (the "Company") is intended and supplied to you, the Company's
 * customer, for use solely and exclusively with products manufactured
 * by the Company. 
 *
 * The software is owned by the Company and/or its supplier, and is 
 * protected under applicable copyright laws. All rights are reserved. 
 * Any use in violation of the foregoing restrictions may subject the 
 * user to criminal sanctions under applicable laws, as well as to 
 * civil liability for the breach of the terms and conditions of this 
 * license.
 *
 * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES, 
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 *
 * This file contains Explicit messaging support for the Connection Object 
 * described in Section 5-4 and Chapter 7 of Volume 1 of the DeviceNet 
 * specification.
 * 
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Ross Fosler			04/28/03	...	
 * 
 *****************************************************************************/

#include	"dnetdef.h"			// Global definitions file

#include 	"typedefs.h"

#include	"conn.h"			// Connection prototypes and symbols

#include	"services.h"		// Service codes
#include	"errors.h"			// Error codes
#include	"class.h"			// Class codes

#include	"route.h"			// Global symbols defined by the router
#include	"dnet.h"			// DeviceNet prototypes and symbols
#include	"frag.h"			// Fragmentation control



#define		_FRAG_SUCCESS	0
#define		_FRAG_TOO_MUCH	1





#define		RXFLAG_FIRST_FRAG		b0
#define		TXFLAG_SEND_ACK			b0
#define		TXFLAG_ACK_STAT			b1
#define		TXFLAG_TX_START			b2
#define		TXFLAG_TX_TIMER_EN		b3
#define		TXFLAG_TX_AGAIN			b4
#define		TXFLAG_TX_FIN			b5


/*********************************************************************
 * Connection related variables
 ********************************************************************/
CONN_EXPL 		uConn1;

unsigned char	uConn1RxBuffer[CONN_EXPLICIT_RX_SIZE];
unsigned char	uConn1TxBuffer[CONN_EXPLICIT_TX_SIZE];



/*********************************************************************
 * Function:        unsigned char _Conn1Create(void)
 *
 * PreCondition:    none
 *
 * Input:       	none	
 *                  
 * Output:      	handle to connection
 *
 * Side Effects:    none
 *
 * Overview:        Returns a handle to the connection 
 *
 * Note:            none
 ********************************************************************/
unsigned char _Conn1Create(void)
{
	//Initialize the connection attributes
	uConn1.attrib.state = _STATE_ESTABLISHED;
	uConn1.attrib.produced_cid.bytes.MSB = uDNet.MACID | 0x80;
	uConn1.attrib.produced_cid.bytes.LSB = 0x60;
	uConn1.attrib.consumed_cid.bytes.MSB = uDNet.MACID | 0x80; 
	uConn1.attrib.consumed_cid.bytes.LSB = 0x80;
	uConn1.attrib.expected_packet_rate.word = 2500;
	uConn1.attrib.wdt_action = _WDT_ACTION_DEFERRED;
	
	_establishFlags.bits.expl = 1;
	_existentFlags.bits.expl = 1;
	
	// Setup the pointer and other info for the receiving side
	uConn1.rx.pMsg = uConn1RxBuffer;
	uConn1.rx.lenMax = CONN_EXPLICIT_RX_SIZE;
	uConn1.rx.fragFlags.byte = 0;
	uConn1.rx.oldFrag = 0;
	
	// Setup the pointer and other info for the transmitting side
	uConn1.tx.pMsg = uConn1TxBuffer;
	uConn1.tx.lenMax = CONN_EXPLICIT_TX_SIZE;
	uConn1.tx.fragFlags.byte = 0;
	uConn1.tx.oldFrag = 0;

	// Put 10000 or (rate)x(4), whichever is greater
	uConn1.timer.word = (uConn1.attrib.expected_packet_rate.word << 2);
	if (uConn1.timer.word < 10000) uConn1.timer.word = 10000;
	
	// Set the time
	uConn1.ack_tmr.word = EXPLICIT_ACK_TIMER;		
			
	//Issue a request to start receiving the CID
	CANSetFilter(uConn1.attrib.consumed_cid.word);
	return (1);
}


/*********************************************************************
 * Function:        unsigned char _Conn1Close(void)
 *
 * PreCondition:    
 *
 * Input:       	none		
 *                  
 * Output:      	status of the close
 *
 * Side Effects:    
 *
 * Overview:        Closes the specified connection 
 *
 * Note:            None
 ********************************************************************/
unsigned char _Conn1Close(void)
{	
	// Transition to the non-existent state
	uConn1.attrib.state = _STATE_NON_EXISTENT;
	
	_establishFlags.bits.expl = 0;
	_existentFlags.bits.expl = 0;
	
	// Issue a request to the driver to stop receiving the message
	CANClrFilter(uConn1.attrib.consumed_cid.word);

	return(1);
}





/*********************************************************************
 * Function:        void _Conn1TimerEvent(void)
 *
 * PreCondition:    
 *
 * Input:       	none		
 *                  
 * Output:      	none
 *
 * Side Effects:    
 *
 * Overview:        Update timer and process any timer events.
 *
 * Note:            None
 ********************************************************************/
void _Conn1TimerEvent(void)
{		
	// Process the watchdog if the packet rate is other than 0
	if (uConn1.attrib.expected_packet_rate.word)
	{
		// Adjust the time
		uConn1.timer.word -= TICK_RESOLUTION;

		// If the wdt expires then change the state of the connection
		if (uConn1.timer.word == 0) 
		{
			// Auto delete the connection
			if (uConn1.attrib.wdt_action == _WDT_ACTION_AUTO_DELETE)
			{ 
				uConn1.attrib.state = _STATE_NON_EXISTENT;
			}
			else 
			
			// Deferred delete (full release is determined outside 
			// of this instance)
			if (uConn1.attrib.wdt_action == _WDT_ACTION_DEFERRED) 
			{
				uConn1.attrib.state = _STATE_DEFERED_DELETE;
			}
		}
	}

#if	FRAGMENTATION_ACK
	// Process fragmentation timer for acknowledged transmission
	if (uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN == 1)
	{
		// Adjust ack timer
		uConn1.ack_tmr.word -= TICK_RESOLUTION;

		// If the ack timer expires then change the frag state
		if (uConn1.ack_tmr.word == 0)
		{	
			// Disable the timer
			uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 0;
			
			// Reset the time
			uConn1.ack_tmr.word = EXPLICIT_ACK_TIMER;

			// If a resend has been requested
			if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1)
			{
				// Kill the message
				// Reset the transmit state
				uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 0;
				uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 0;
				uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 0;

				// Set flag indicating completion
				_txFinFlags.bits.expl = 1;
			}
			else
			{
				// Issue a resend
				uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 1;
				_txFlag.bits.expl = 1;
			}
		}
	}
#endif
}




/*********************************************************************
 * Function:        void _Conn1RxEvent(void)
 *
 * PreCondition:    
 *
 * Input:       	none	
 *                  
 * Output:      	none
 *
 * Side Effects:    
 *
 * Overview:        Process data for this connection.
 *
 * Note:            This event occures when data has been received
 *					for this connection instance.
 ********************************************************************/
void _Conn1RxEvent(void)
{
	BYTE header, service, frag, count, type, len;

	// Set the size of classId depending on what has been specified
	#if (CLASS_WIDTH_16BIT)
	UINT classId;
	#else
	BYTE classId;
	#endif
	
	len.byte = CANGetRxCnt();
	
	// Extract the header	
	header.byte = CANGetRxDataSIG(0);
		
#if	FRAGMENTATION_ACK				
	// If fragmented
	if (header.bits.b7)
	{
		// Process only if there is sufficient data to process the connection
		if (len.byte > 2)
		{
			// Point to the frag byte and copy it
			frag.byte = CANGetRxDataSIG(1);
			
			// Point to the service
			//pRxData++;
			
			// Get the fragment type and count
			type.byte = frag.byte & 0xC0;
			count.byte = frag.byte & 0x3F;
		
			// If the header MAC equals the allocated MasterMACID then 
			// process the message fragment	
			if (((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0)
			{			
				// Remember the header
				uConn1.rx.header = header.byte; 
					
				// Process the fragment
				switch (type.byte)
				{
					// Received first fragment
					case 0x00:
						// The first fragment must always have a frag byte of 0
						if (frag.byte == 0)
						{
							// Copy the fragment to the buffer
							CANGetRxDataTyp2(uConn1.rx.pMsg + 1);
							
							// Store the header
							*uConn1.rx.pMsg = header.byte;
				
							// Adjust the length minus the fragment control byte
							uConn1.rx.len = len.byte - 1;
												
							// Request to issue an ACK with status	
							uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
							uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0;
							_txFlag.bits.expl = 1;
											
							// Reset the old fragment
							uConn1.rx.oldFrag = 0;
				
							// Indicate the first fragment has been received
							uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 1;
						}
						break;
						
					// Received a middle or last fragment
					case 0x40:
					case 0x80:
						// If this frag is the same as the previous then re-ack
						if (uConn1.rx.oldFrag == frag.byte)
						{
							// Set the status & request the hardware to send the ACK
							uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
							uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0;
							_txFlag.bits.expl = 1;
						}
						else
					
						// Continue if the first fragment has been received
						if (uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG)
						{						
							// Process the current fragment
							if (((uConn1.rx.oldFrag + 1) & 0x3F) == count.byte)
							{
								// if the buffer is large enough
								if ((uConn1.rx.len + (len.byte - 1)) < uConn1.rx.lenMax)
								{
						
									// Copy this fragment to the buffer
									CANGetRxDataTyp2(uConn1.rx.pMsg + uConn1.rx.len);
					
									// Store the length minus the fragment control byte and header
									uConn1.rx.len += (len.byte - 2);
								
									// Save the current fragment information
									uConn1.rx.oldFrag = frag.byte;
									
									// If this the last fragment in the sequence
									if (type.byte == 0x80)
									{
										// Indicate message has been received
										_rxFlag.bits.expl = 1;
									}
								
									// Set the status & request the hardware to send the ACK				
									uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
									uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 0;
									_txFlag.bits.expl = 1;
								}
							
								//else send an error ack indicating too much data		
								else
								{
									// Set the status & request the hardware to send the ACK				
									uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
									uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 1;
									_txFlag.bits.expl = 1;
								
									// Reset to the initial state
									uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;
								}
							}
						
							// Toss the fragment and reset to the first state
							else
							{
								// Reset to the initial state
								uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;
							}
						}
					
						// Fragment not expected
						else
						{
							// Reset to the initial state	
							uConn1.rx.fragFlags.bits.RXFLAG_FIRST_FRAG = 0;	
						}
						break;
						
										
					// Received an ACK
					case 0xC0:
						// Process ack if expecting it
						if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1)
						{
							// Stop the acknowledge timer if it was running
							uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 0;

							// Reset the retry flag if it was set
							uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN = 0;

							// If the last transmission has been sent
							if (uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN == 1)
							{
								// Reset the transmit state
								uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 0;
								uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 0;
							}
							else
							{
								// Start up the next transmission
								_txFlag.bits.expl = 1;
							}
						}
						break;
					}
							
							
							
				
				// Put the connection into the established state
				uConn1.attrib.state = _STATE_ESTABLISHED;
				_establishFlags.bits.expl = 1;
				
				// Reset the connection wdt
				uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2;
			}
		}
	}
#else
	// If fragmented
	if (header.bits.b7)
	{
		// Process only if there is sufficient data to process the connection
		if (len.byte > 2)
		{
			// If the header MAC equals the allocated MasterMACID then 
			// process the message fragment	
			if (((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0)
			{
				// Request to issue an ACK with error status	
				uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 1;
				uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT = 1;
				_txFlag.bits.expl = 1;
			}
		}
	}
#endif

	// else process a non-fragmented message
	else
	{ 
		// Process only if there is sufficient data to process the connection
		if (len.byte > 1)
		{
			// Extract the service ID  
			service.byte = CANGetRxDataSIG(1);
		
			// If the header MAC equals the allocated MasterMACID or if the release
			// connection service is requested then process the message.
			// (refer to section 5-5.4.2)
			#if (CLASS_WIDTH_16BIT)
			classId.bytes.LSB = CANGetRxDataSIG(2);
			classId.bytes.MSB = CANGetRxDataSIG(3);
			if (((classId.word == CLASS_DEVICENET) && (service.byte == SRVS_RELEASE_CONN)) ||
				(header.byte ^ uDNet.AllocInfo.MasterMACID & 0x3F) == 0)
			#else
			classId.byte = CANGetRxDataSIG(2);
			if (((classId.byte == CLASS_DEVICENET) && (service.byte == SRVS_RELEASE_CONN)) ||
				((header.byte ^ uDNet.AllocInfo.MasterMACID) & 0x3F) == 0)
			#endif
			{
				// Remember the header
				uConn1.rx.header = header.byte;; 
				
				// Get the count		
				uConn1.rx.len = CANGetRxCnt();
		
				// Copy the message to the connection buffer
				CANGetRxDataTyp0(uConn1RxBuffer);
			
				// Indicate message has been received (located in conn.c)	
				_rxFlag.bits.expl = 1;
		
				// Put the connection into the established state
				uConn1.attrib.state = _STATE_ESTABLISHED;
				_establishFlags.bits.expl = 1;
				
				// Reset the connection wdt
				uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2;
			}
		}
	}
	
	// Release the hardware to continue receiving
	CANRead();
}



 
/*********************************************************************
 * Function:        void _Conn1TxOpenEvent(void)
 *
 * PreCondition:    none
 *
 * Input:       	none	
 *                  
 * Output:      	none
 *
 * Side Effects:    none
 *
 * Overview:        Process
 *
 * Note:            This event occurs when the buffer is available 
 *					for this connection instance to transmit.
 ********************************************************************/
void _Conn1TxOpenEvent(void)
{
	BYTE header;
	unsigned char *pTxData;
	
	//2022-10 lifeng  加入，原作者的严重BUG
	CANPutTxCID(uConn1.attrib.produced_cid.word);

	// Get the pointer to the CAN transmit buffer
	pTxData = CANGetTxDataPtr();

	// If acknowledge requested then force fragment processing
	if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1)
	{
		header.bits.b7 = 1;
	}
	
	// Else get the header from top level
	else
	{
		header.byte = *uConn1TxBuffer;
	}
	
#if	FRAGMENTATION_ACK
	// If fragmented
	if (header.bits.b7)
	{
		// If in the send ack state as a result of a receive then
		if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1)
		{
			// Copy the header and the fragment count (header should be 
			// the same as the received header)
			*pTxData = uConn1.rx.header; pTxData++;
			*pTxData = uConn1.rx.oldFrag | 0xC0; pTxData++;

			// Send a success ack 
			if (uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT == 0)
			{
				*pTxData = _FRAG_SUCCESS;
			}
			// or send an error ack
			else
			{
				*pTxData = _FRAG_TOO_MUCH;
			}
			
			// Set the length of the message
			CANPutTxCnt(3);
		}	
		else 

		// If a resend has been requested
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1)
		{
			// Copy the header
			*pTxData = *uConn1TxBuffer; pTxData++;
			
			// Copy the last fragment
			*pTxData = uConn1.tx.oldFrag;
			
			// Copy 6 bytes of the packet
			CANPutTxDataTyp2(uConn1TxBuffer + uConn1.tx.index);
		}
		else
		
		// If the first fragmented transmit progress has been started already
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1)
		{
			// Copy the header
			*pTxData = *uConn1TxBuffer; pTxData++;
			
			// Adjust the fragment byte
			uConn1.tx.oldFrag++;
			
			// Adjust the index
			uConn1.tx.index += 7;
			
			// If last fragment
			if (uConn1.tx.len < 7)
			{
				// Indicate the last fragment has been queued to send
				uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN = 1;
				
				// Set the type
				//uConn1.tx.oldFrag = (uConn1.tx.oldFrag & 0x3F) | 0xC0;
				uConn1.tx.oldFrag = (uConn1.tx.oldFrag & 0x3F) | 0x80;      //lifeng 2022-10
				
				// Set the length of the message
				CANPutTxCnt(uConn1.tx.len + 2);
				
				// Adjust the length
				uConn1.tx.len = 0;
			}
			
			// Middle fragment
			else
			{
				// Set the type
				uConn1.tx.oldFrag = (uConn1.tx.oldFrag & 0x3F) | 0x80;
				
				// Set the length of the message
				CANPutTxCnt(8);
				
				// Adjust the length
				uConn1.tx.len -= 6;
			}
			
			// Copy the fragment info
			*pTxData = uConn1.tx.oldFrag;
			
			// Copy 6 bytes of the packet
			CANPutTxDataTyp2(uConn1TxBuffer + uConn1.tx.index);
		}

		// Transmit has not been started, so que the first message
		else
		{
			// Copy the header
			*pTxData = *uConn1TxBuffer; pTxData++;
			
			// Set the frag byte to first fragment 
			*pTxData = uConn1.tx.oldFrag = 0;
			
			// Set the index
			uConn1.tx.index = 0;                //lifeng 2022-10
			//uConn1.tx.index = 1;
			
			// Copy the first 6 bytes of the packet
			CANPutTxDataTyp2(uConn1TxBuffer + 1);
				
			// Adjust the length by 7, i.e. header and 6 data bytes
			uConn1.tx.len = uConn1.tx.len - 7;
					
			// Set the length of the message
			CANPutTxCnt(8);
			
			// Indicate the first message has been started
			uConn1.tx.fragFlags.bits.TXFLAG_TX_START = 1;
		}
	}
#else
	// If fragmented
	if (header.bits.b7)
	{
		// If in the send ack state as a result of a receive then
		if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1)
		{
			// Copy the header and the fragment count (header should be 
			// the same as the received header)
			*pTxData = uConn1.rx.header; pTxData++;
			*pTxData = uConn1.rx.oldFrag | 0xC0; pTxData++;

			// Send a success ack 
			if (uConn1.tx.fragFlags.bits.TXFLAG_ACK_STAT == 0)
			{
				*pTxData = _FRAG_SUCCESS;
			}
			// or send an error ack
			else
			{
				*pTxData = _FRAG_TOO_MUCH;
			}
			
			// Set the length of the message 
			CANPutTxCnt(3);
		}
		else
		{
			//Clear the transmit flag to open access to the write buffer
			_txFlag.bits.expl = 0;
			return;
		}
	}
#endif  


	// else process a non-fragmented message
	else
	{
		// Copy the message to the hardware buffer
		CANPutTxDataTyp0(uConn1TxBuffer);
		
		// Set the length of the message
		CANPutTxCnt(uConn1.tx.len);
	}	
	
	//Clear the transmit flag to open access to the write buffer
	_txFlag.bits.expl = 0;
	// Request the hardware to queue the message to send
	CANSend(1);
}


/*********************************************************************
 * Function:        void _Conn1TxEvent(void)
 *
 * PreCondition:    
 *
 * Input:       	none
 *                  
 * Output:      	none
 *
 * Side Effects:    
 *
 * Overview:        Process data for this connection.
 *
 * Note:            This event occurs when the buffer has successfully
 *					placed the requested data on the bus.
 ********************************************************************/
void _Conn1TxEvent(void)
{
	BYTE header;
	//unsigned char *pTxData;
	
		 
	// If acknowledge requested then force fragment processing
	if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1)
	{
		header.bits.b7 = 1;
	}
	
	// Else get the header from top level
	else
	{
		header.byte = *uConn1TxBuffer;
	}	
		
	// If fragmented
	if (header.bits.b7)
	{
		// If in the send ack state as a result of a receive then
		if (uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK == 1)
		{
			// Remove the send ack request
			uConn1.tx.fragFlags.bits.TXFLAG_SEND_ACK = 0;
		}
		
	#if	FRAGMENTATION_ACK
		else

		// If a resend has been requested
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_AGAIN == 1)
		{
			// Start the acknowledge timer
			uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 1;
		}
		else

		// If the last transmission has been sent
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_FIN == 1)
		{
			// Set flag indicating all data has been placed on the bus
			_txFinFlags.bits.expl = 1;
		}
		else

		// If the first fragmented transmit progress has been started already
		if (uConn1.tx.fragFlags.bits.TXFLAG_TX_START == 1)
		{
			// Start the acknowledge timer
			uConn1.tx.fragFlags.bits.TXFLAG_TX_TIMER_EN = 1;
		}
	#endif
	}
	
	// Not fragmented
	else
	{
		// Set flag indicating data has been placed on the bus
		_txFinFlags.bits.expl = 1;
	}
}





/*********************************************************************
 * Function:        unsigned char _Conn1ExplicitEvent(void)
 *
 * PreCondition:    
 *
 * Input:       	none	
 *                  
 * Output:      	status
 *
 * Side Effects:    
 *
 * Overview:        Handle explicit messaging
 *
 * Note:            None
 ********************************************************************/
unsigned char _Conn1ExplicitEvent(void)
{
	switch(mRouteGetServiceID())
   	{
   		case SRVS_GET_ATTRIB_SINGLE:
   			return (_Conn1GetAttrib());
   		case SRVS_SET_ATTRIB_SINGLE:
   			return (_Conn1SetAttrib());
   	   	default:
   			mRoutePutError(ERR_SERVICE_NOT_SUPPORTED);
   			break;
   	}
		
	return (1);
}


/*********************************************************************
 * Function:        unsigned char _Conn1GetAttrib()
 *
 * PreCondition:    
 *
 * Input:       	none
 *                  
 * Output:      	status
 *
 * Side Effects:    
 *
 * Overview:        Handle explicit messaging
 *
 * Note:            None
 ********************************************************************/
unsigned char _Conn1GetAttrib(void)
{
	UINT	work;

	switch (mRouteGetAttributeID())
	{
		case	_ATTRIB_STATE:
			mRoutePutByte(uConn1.attrib.state);
			break;
		case	_ATTRIB_INSTANCE_TYPE:
			mRoutePutByte(0);
			break;
		case	_ATTRIB_CLASS_TRIGGER:
			mRoutePutByte(0x83);
			break;
		case 	_ATTRIB_PRODUCED_CID:
			work.word = (uConn1.attrib.produced_cid.word >> 5);
			mRoutePutByte(work.bytes.LSB);
			mRoutePutByte(work.bytes.MSB);
			break;
		case	_ATTRIB_CONSUMED_CID:
			work.word = (uConn1.attrib.consumed_cid.word >> 5);
			mRoutePutByte(work.bytes.LSB);
			mRoutePutByte(work.bytes.MSB);
			break;	
		case 	_ATTRIB_INITIAL_COMM_CHAR:
			mRoutePutByte(0x21);
			break;
		case	_ATTRIB_PRODUCED_CONN_SIZE:
			mRoutePutByte(uConn1.tx.lenMax);
			mRoutePutByte(0);
			break;
		case	_ATTRIB_CONSUMED_CONN_SIZE:
			mRoutePutByte(uConn1.rx.lenMax);
			mRoutePutByte(0);
			break;
		case	_ATTRIB_EXPECTED_RATE:
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.LSB);
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.MSB);
			break;
		case	_ATTRIB_WDT_ACTION:
			mRoutePutByte(uConn1.attrib.wdt_action);
			break;
		case	_ATTRIB_PRODUCED_CONN_PATH_LEN:
		case	_ATTRIB_CONSUMED_CONN_PATH_LEN:
			mRoutePutByte(0);
			mRoutePutByte(0);
			break;
		case	_ATTRIB_PRODUCED_CONN_PATH:
		case	_ATTRIB_CONSUMED_CONN_PATH:
			break;
		default:
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED);
			break;
	}
	return(1);
}




/*********************************************************************
 * Function:        unsigned char _Conn1SetAttrib(void)
 *
 * PreCondition:    
 *
 * Input:       	none
 *                  
 * Output:      	status
 *
 * Side Effects:    
 *
 * Overview:        Handle explicit messaging
 *
 * Note:            None
 ********************************************************************/
unsigned char _Conn1SetAttrib(void)
{
	unsigned char 	work;

	switch (mRouteGetAttributeID())
	{	
		case	_ATTRIB_EXPECTED_RATE:
			// Read in the requested packet rate
			uConn1.attrib.expected_packet_rate.bytes.LSB = mRouteGetByte();
			uConn1.attrib.expected_packet_rate.bytes.MSB = mRouteGetByte();

			// Get the ls bits
			work = uConn1.attrib.expected_packet_rate.bytes.LSB & (TICK_RESOLUTION - 1);

			// Remove the ls bits from desired resolution
			uConn1.attrib.expected_packet_rate.bytes.LSB &= (~(TICK_RESOLUTION - 1));
			
			// Round up if necessary
			if (work) uConn1.attrib.expected_packet_rate.word += (TICK_RESOLUTION);

			// Return the value actually used
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.LSB);
			mRoutePutByte(uConn1.attrib.expected_packet_rate.bytes.MSB);

			// Set the timer 4x (section 5-4.4.2)
			uConn1.timer.word = uConn1.attrib.expected_packet_rate.word << 2; 
			break;
			
		case	_ATTRIB_WDT_ACTION:
			work = mRouteGetByte();
			if ((work == _WDT_ACTION_DEFERRED) || (work == _WDT_ACTION_AUTO_DELETE))
			{
				uConn1.attrib.wdt_action = work;
			}
			else
			{
				mRoutePutError(ERR_INVALID_ATTRIB_VALUE);
			}
			break;
		

		case	_ATTRIB_PRODUCED_CONN_SIZE:
		case	_ATTRIB_CONSUMED_CONN_SIZE:
		case	_ATTRIB_STATE:
		case	_ATTRIB_INSTANCE_TYPE:
		case	_ATTRIB_CLASS_TRIGGER:
		case 	_ATTRIB_PRODUCED_CID:
		case	_ATTRIB_CONSUMED_CID:
		case 	_ATTRIB_INITIAL_COMM_CHAR:
		case	_ATTRIB_PRODUCED_CONN_PATH_LEN:
		case	_ATTRIB_PRODUCED_CONN_PATH:
		case	_ATTRIB_CONSUMED_CONN_PATH_LEN:
		case	_ATTRIB_CONSUMED_CONN_PATH:
			mRoutePutError(ERR_ATTRIB_NOT_SETTABLE);
			break;
			
		default:
			mRoutePutError(ERR_ATTRIB_NOT_SUPPORTED);
			break;
	}
	return(1);
}




